package io2.nio.reactor;

import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.spi.AbstractSelectableChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public abstract class EventLoop extends Thread {
    // 保存任务的队列
    private ConcurrentLinkedQueue<Runnable> taskQueue = new ConcurrentLinkedQueue();
    // 每个EventLoop都有一个自己的selector选择器
    private Selector selector;
    // 是否是在运行
    private volatile boolean isRun = false;

    /**
     * 处理事件的方法
     * @param channel
     */
    public abstract void handle(Object channel, SelectionKey key);

    public EventLoop(String name) {
        this.setName(name);
        try {
            selector = Selector.open();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 执行任务
     * 将任务放入队列中
     * @param runnable
     */
    public void execute(Runnable runnable) {
        taskQueue.add(runnable);
    }

    /**
     * 启动eventLoop
     */
    public void doStart() {
        if(!isRun) {
            isRun = true;
            start();
        }
    }

    /**
     * 注册channel到selector上
     * @param channel
     * @return
     */
    public SelectionKey register(final AbstractSelectableChannel channel) {
        FutureTask<SelectionKey> futureTask = new FutureTask(() -> channel.register(selector, 0, channel));
        // 提交一个任务来注册
        execute(futureTask);
        try {
            // 订阅成功后，返回这个订阅的selectionKey
            return futureTask.get();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
//        try {
//            return channel.register(selector, 0, channel);
//        } catch (ClosedChannelException e) {
//            e.printStackTrace();
//        }
        return null;
    }

    @Override
    public void run() {
        // TODO 轮训事件， 处理任务
        for(;;) {
            Runnable task;
            // 如果队列中有任务，就执行任务
            if ((task = taskQueue.poll()) != null)
                task.run();

            try {
                int n = selector.select(100);
//                System.out.println("selected num -> " + n);
            } catch (IOException e) {
                e.printStackTrace();
            }

            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            if(selectionKeys.size() == 0)
                continue;
            Iterator<SelectionKey> iterator = selectionKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = iterator.next();
                iterator.remove();
                // 调用处理事件的方法
                handle(key.attachment(), key);
            }
        }
    }
}
